﻿using System;
using System.Runtime.Serialization;

namespace Notoric.Model.Packaging
{
    /// <summary>
    /// The exception that is thrown when the package has not the expected format.
    /// </summary>
    /// <remarks>
    /// The exception uses two user-defined fields, that can be retrieved via the <see cref="Exception.Data"/> collection:
    /// <list type="bullet">
    /// <item><i>CanConvert</i> - Indicates whether the library is able to convert the current package to the correct format</item>
    /// <item><i>ErrorType</i> - Describes the nature of the problem</item>
    /// </list>
    /// </remarks>
    [Serializable]
    public class WrongPackageFormatException : Exception
    {
        #region Constructors
        
        /// <summary>
        /// Creates a new <see cref="WrongPackageFormatException"/> instance.
        /// </summary>
        /// <param name="errorType">
        /// <para>
        /// Type: <see cref="ExceptionType"/>
        /// </para>
        /// <para>
        /// A <see cref="ExceptionType"/> value describing the nature of the problem.
        /// </para>
        /// </param>
        /// <param name="message">
        /// <para>
        /// Type: <see cref="System.String"/>
        /// </para>
        /// <para>
        /// Message that describes the current exception.
        /// </para>
        /// </param>
        public WrongPackageFormatException(ExceptionType errorType, string message) 
            : base(message) 
        {
            Data["CanConvert"] = false;
            Data["ErrorType"] = errorType;
        }

        /// <summary>
        /// Creates a new <see cref="WrongPackageFormatException"/> instance.
        /// </summary>
        /// <param name="errorType">
        /// <para>
        /// Type: <see cref="ExceptionType"/>
        /// </para>
        /// <para>
        /// A <see cref="ExceptionType"/> value describing the nature of the problem.
        /// </para>
        /// </param>
        /// <param name="message">
        /// <para>
        /// Type: <see cref="System.String"/>
        /// </para>
        /// <para>
        /// Message that describes the current exception.
        /// </para>
        /// </param>
        /// <param name="inner">
        /// <para>
        /// Type: <see cref="Exception"/>
        /// </para>
        /// <para>
        /// <see cref="Exception"/> instance that caused the current exception.
        /// </para>
        /// </param>
        public WrongPackageFormatException(ExceptionType errorType, string message, Exception inner) 
            : base(message, inner) 
        {
            Data["CanConvert"] = false;
            Data["ErrorType"] = errorType;
        }

        /// <summary>
        /// Creates a new <see cref="WrongPackageFormatException"/> instance.
        /// </summary>
        /// <param name="errorType">
        /// <para>
        /// Type: <see cref="ExceptionType"/>
        /// </para>
        /// <para>
        /// A <see cref="ExceptionType"/> value describing the nature of the problem.
        /// </para>
        /// </param>
        /// <param name="canConvert">
        /// <para>
        /// Type: <see cref="System.Boolean"/>
        /// </para>
        /// <para>
        /// Indicates whether the library is able to convert the current package
        /// to the expected format.
        /// </para>
        /// </param>
        /// <param name="message">
        /// <para>
        /// Type: <see cref="System.String"/>
        /// </para>
        /// <para>
        /// Message that describes the current exception.
        /// </para>
        /// </param>
        public WrongPackageFormatException(ExceptionType errorType, bool canConvert, string message)
            : base(message)
        {
            Data["CanConvert"] = canConvert;
            Data["ErrorType"] = errorType;
        }

        /// <summary>
        /// Creates a new <see cref="WrongPackageFormatException"/> instance.
        /// </summary>
        /// <param name="errorType">
        /// <para>
        /// Type: <see cref="ExceptionType"/>
        /// </para>
        /// <para>
        /// A <see cref="ExceptionType"/> value describing the nature of the problem.
        /// </para>
        /// </param>
        /// <param name="canConvert">
        /// <para>
        /// Type: <see cref="System.Boolean"/>
        /// </para>
        /// <para>
        /// Indicates whether the library is able to convert the current package
        /// to the expected format.
        /// </para>
        /// </param>
        /// <param name="message">
        /// <para>
        /// Type: <see cref="System.String"/>
        /// </para>
        /// <para>
        /// Message that describes the current exception.
        /// </para>
        /// </param>
        /// <param name="inner">
        /// <para>
        /// Type: <see cref="Exception"/>
        /// </para>
        /// <para>
        /// <see cref="Exception"/> instance that caused the current exception.
        /// </para>
        /// </param>
        public WrongPackageFormatException(ExceptionType errorType, bool canConvert, string message, Exception inner)
            : base(message, inner)
        {
            Data["CanConvert"] = canConvert;
            Data["ErrorType"] = errorType;
        }
        
        /// <summary>
        /// Creates a new <see cref="WrongPackageFormatException"/> instance.
        /// </summary>
        /// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
        /// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination.</param>
        protected WrongPackageFormatException(SerializationInfo info, StreamingContext context) : base(info, context) { }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets a value indicating whether the library 
        /// is able to convert the package to the expected format.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="System.Boolean"/>
        /// </para>
        /// <para>
        /// Indicates whether the library is able to convert the current package
        /// to the expected format.
        /// </para>
        /// <para>
        /// This property wraps <see cref="Exception.Data"/>["CanConvert"].
        /// </para>
        /// </value>
        public bool CanConvert
        {
            get { return (bool)Data["CanConvert"]; }
        }

        /// <summary>
        /// Gets a value that describes the nature of the problem.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="ExceptionType"/>
        /// </para>
        /// <para>
        /// A <see cref="ExceptionType"/> value describing the nature of the problem.
        /// </para>
        /// <para>
        /// This property wraps <see cref="Exception.Data"/>["ErrorType"].
        /// </para>
        /// </value>
        public ExceptionType ErrorType
        {
            get { return (ExceptionType)Data["ErrorType"]; }
        }

        #endregion

        /// <summary>
        /// Describes the nature of the problem.
        /// </summary>
        public enum ExceptionType
        {
            /// <summary>
            /// The package is corrupted.
            /// </summary>
            CorruptedPackage,
            /// <summary>
            /// The package is in a correct format but older version.
            /// </summary>
            OldVersion,
            /// <summary>
            /// The package has an unknown format and cannot be read.
            /// </summary>
            UnknownFormat
        }
    }
}
